<?php

namespace App\Console\Server;

use App\Console\Base;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Support\Carbon;
use Swoole\Process;
use common\enum\QueueEnum;
use Illuminate\Support\Facades\Artisan;
use Swoole\Table;

class SwooleQueue extends Base
{
    /**
     * 控制台命令 signature 的名称。
     *
     * @var string
     */
    protected $signature = 'uniform:swoole_queue {--queue=' . QueueEnum::COMMAND . '} {--worker_num=0}';

    /**
     * 控制台命令说明。
     *
     * @var string
     */
    protected $description = '使用swoole的多进程管理跑queue';

    /**
     * 运行队列参数
     * 
     * @var array
     */
    protected $queueOption = [];

    protected $workerMap;

    /**
     * 执行控制台命令。
     *
     * @return mixed
     */
    public function handle()
    {

        $this->queueOption = config('app.queue.options');
        $this->queueOption["--queue"] = $this->option('queue');
        $workerNum = $this->option('worker_num') > 0 ? $this->option('worker_num') : config('app.queue.worker_num');
        $this->workerMap = new Table($workerNum);
        $this->workerMap->column('id', Table::TYPE_INT, 8);
        $this->workerMap->create();
        $this->runQueue($workerNum);
        while (true) {
            $ret = Process::wait();
            $this->rebootProcess($ret);
        }
    }

    public function runQueue($num)
    {
        while ($num > 0) {
            $this->createProcess($num);
            $num--;
        }
    }

    public function createProcess($id)
    {
        $process = new Process(function (Process $worker) use ($id) {
            swoole_set_process_name('uniform:swoole_queue:' . $this->option('queue') . '-' . $id);
            Artisan::call('queue:work', $this->queueOption);
        });
        $pid = $process->start();
        $this->workerMap->set($pid, ['id' => $id]);
    }

    public function rebootProcess($ret)
    {
        $pid = $ret['pid'];
        $id = $this->workerMap->get($pid, 'id');
        $this->workerMap->del($pid);
        $this->createProcess($id);
        $this->error("Worker $pid reboot!");
    }
}
